1124. 表现良好的最长时间段
1124. 表现良好的最长时间段
Similar Question
Solution Tips
方案一: 前缀和变体
525. 连续数组 要求的是和为 0 的, 这一题要求的是和大于 0 的.
var longestWPI = function (hours) {
// 大于 8 小时的视为 1
// 小于 8 小时的视为 -1
// 计算前缀和, 只要前缀和大于 0, 就可以去统计前面的有多少 减去之后依然大于 0 的, 就是长度
// 假如当前前缀和为 -5, 那么前面的 map[-5] 以上的都可以减去, 减去以后和就是正数了, 剩下的就是符合题意的长度
// 要找的是和大于 0 的子数组
// 前缀和大于0的话, 前缀长度就是最长的
// 前缀和小于0的话, 就通过哈希map找有没有 target 减完之后能大于 0 的
const map = {};
let res = 0;
let prefixSum = 0;
for (let i = 0; i < hours.length; i++) {
const item = hours[i] > 8 ? 1 : -1;
prefixSum += item;
if (map[prefixSum] === undefined) {
// 不需要数组, 最早出现的距离最远, 贪心, 更符合题意
map[prefixSum] = i;
}
// else {
// map[prefixSum] = [i];
// }
if (prefixSum > 0) {
// 直接比较长度
res = Math.max(res, i + 1);
}
else {
// 找找前面的哈希表中, 有没有出现过最远的
// 找 keys 中小于 prefixSum 的, 减去之后的子数组就是大于 0 的了
// 比如 prefixSum 当前为 -5, 找到一个 -6 的前缀和, 减去之后剩余 1
// 每次都需要遍历一次 map, 需要优化, 让 map keys 有序
for (const [sum, index] of Object.entries(map).sort(([key1], [key2]) => key1 - key2)) {
if (sum < prefixSum) {
res = Math.max(i - index, res);
}
else {
break;
}
}
}
}
return res;
};
因为前缀和是从 0 开始的, 一个小于 - 1 的前缀和, 索引一定是位于 -1 之后的, 这样才能不断累积负数大于 -1. 基于这一点, 其实只需要找到 prefixSum[i] - 1
的 target 即可, 就完全转换为熟悉的题目了
var longestWPI = function(hours) {
const n = hours.length;
const map = new Map();
let s = 0, res = 0;
for (let i = 0; i < n; i++) {
s += hours[i] > 8 ? 1 : -1;
if (s > 0) {
res = Math.max(res, i + 1);
} else {
if (map.has(s - 1)) {
res = Math.max(res, i - map.get(s - 1));
}
}
if (!map.has(s)) {
map.set(s, i);
}
}
return res;
};